package study.stream.分支合并并行求和;

import java.util.Arrays;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * @Author 刘伟涛
 * @Date 2023/6/26 15:32
 **/
public class ForkJoinSumCalculator extends java.util.concurrent.RecursiveTask{

    private final long[] numbers;
    private final int start;
    private final int end;

    public static final long THRESHOLD = 10_000;

    public ForkJoinSumCalculator(long[] numbers){
        this(numbers,0,numbers.length);
    }

    private ForkJoinSumCalculator(long[] numbers,int start,int end){
        this.numbers = numbers;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        int length = end - start;
        if(length <= THRESHOLD){
            return computeSequentially();
        }
        ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers,start,start + length/2);
        //开启新的线程，执行计算。
        leftTask.fork();
        ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers,start + length/2,end);
        //计算右部分数组结果，有可能继续分割
        Long rightResult = rightTask.compute();
        //读取leftTask执行的结果
        Long leftResult = (Long) leftTask.join();
        return rightResult + leftResult;
    }

    private long computeSequentially(){
        long sum = 0;
        for (int i = start; i < end; i++) {
            sum += numbers[i];
        }
        /*sum = Arrays.stream(numbers).parallel().reduce(0L,Long::sum);*/
        /*你好*/
        return sum;
    }

    public static long forkJoinSum(long n){
        long[] numbers = LongStream.rangeClosed(1,n).toArray();
        ForkJoinTask<Long> task = new ForkJoinSumCalculator(numbers);
        //启用线程执行compute方法
        new ForkJoinPool().invoke(task);
        return task.join();
    }
}
